﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Base;

namespace Server
{
    /// <summary>
    /// User info class
    /// </summary>
    public struct ClientInfo
    {
        private string _UserNickName;
        public string UserNickName
        {
            get { return _UserNickName;}
            set { _UserNickName = value;}
        }
        private Socket _cSocket;
        public Socket cSocket
        {
            get { return _cSocket; }
            set { _cSocket = value;}
        }
        public ClientInfo(string str, Socket sock)
        {
            _UserNickName = str;
            _cSocket = sock;
        }
    }

    /// <summary>
    /// Server class
    /// </summary>
    public class TCPServer
    {
        public Socket sSocket
        {
            get;
            set;
        }
        public IPAddress sIPAdress
        {
            get;
            set;
        }
        public BaseFunctional sBase
        {
            get;
            set;
        }
        public Message sMessage
        {
            get;
            set;
        }

        private List<ClientInfo> ClientsList
        {
            get;
            set;
        }

        public TCPServer()
        {
            sMessage = new Message();
            sBase = new BaseFunctional();
            ClientsList = new List<ClientInfo>();
        }
        /// <summary>
        /// Function of server running
        /// </summary>
        /// <param name="PORT">port number to listen</param>
        public void ServerRun(int PORT)
        {
            sSocket = sBase.CreateSocket(PORT);
            while (true)
            {
                sSocket.Bind(sBase.GetEndPoint());
                while (true)
                {
                    sSocket.Listen(20);
                
                    Socket newSocket = sSocket.Accept();

                    byte[] bytes = new byte[1024];
                    newSocket.Receive(bytes);
                    sMessage = sBase.DeSerialization(bytes);
                    switch (sMessage.CommandType)
                    {
                        case Command.Registration:
                            RegistrationUser(newSocket);
                            break;
                        case Command.Login:
                            LoginUser(newSocket);
                            break;
                        case Command.Logout:
                            LogoutUser();
                            break;
                        case Command.Message:
                            MessageUser();
                            break;
                        case Command.PrivateMessage:
                            PrivateMessageUser(newSocket);
                            break;
                    }
                }
            }
        }

        public void RegistrationUser(Socket sock)
        {
            Message mes = new Message();
            /// Здесь вставить проверку, существует ли уже такой зарегистрированный юзер в базе
            /// Если не существует, то процесс добавления юзера в базу юзеров
            /// Усли все успешно, то возвращаем сообщение об успешном добавлении юзера
            mes.Answer = "OK";
            mes.MessageText = "User added to data base successfully...";
            sock.Receive(sBase.Serialization(mes));
        }
        public void LoginUser(Socket sock)
        {
            Message mes = new Message();
            /// Здесь вставить проверку, существует ли уже такой зарегистрированный юзер в базе
            /// Если не сужествет, то
            // mes.Answer = "NO";
            // mes.MessageText = "Please, registrate!";
            
            foreach (ClientInfo Info in ClientsList)
                if (Info.UserNickName == sMessage.UserNickName)
                {
                    mes.Answer = "NO";
                    mes.MessageText = "This user is already in chart-room";
                    sock.Receive(sBase.Serialization(mes));
                }
                else
                {
                    ClientsList.Add(new ClientInfo(sMessage.UserNickName, sock));
                    mes.Answer = "OK";
                    sock.Receive(sBase.Serialization(mes));
                    mes.MessageText = "User " + sMessage.UserNickName + " entered into chat-room...";
                    SendBroadcastMessage(mes);
                }
        }

        public void LogoutUser()
        {
            foreach(ClientInfo Info in ClientsList)
                if (Info.UserNickName == sMessage.UserNickName)
                {
                    sBase.ShutDownSocket(Info.cSocket);
                    ClientsList.Remove(Info);
                }
            return;
        }

        public void MessageUser()
        {
            Message mes = new Message();
            mes.Answer = "OK";
            mes.MessageText = sMessage.MessageText;
            SendBroadcastMessage(mes);
        }
        public void SendBroadcastMessage(Message mes)
        {
            try
            {
                for (int i = 0; i < ClientsList.Count; i++)
                    ClientsList[i].cSocket.Receive(sBase.Serialization(mes));
            }
            catch(Exception exc)
            {
                
            }
        }
        public void RefreshUsersList()
        {
            int i=0;
            while(i < ClientsList.Count)
            {
                if (ClientsList[i].cSocket.Connected == false)
                    DisconnectUser(ClientsList[i].UserNickName);
                else
                    i++;
            }
        }
        public void DisconnectUser(string name)
        {
            foreach (ClientInfo Info in ClientsList)
                if (Info.UserNickName == name)
                {
                    sBase.ShutDownSocket(Info.cSocket);
                    ClientsList.Remove(Info);
                    break;
                }
        }
        public void PrivateMessageUser(Socket sock)
        {
            Message mes = new Message();
            mes.Answer = "OK";
            mes.MessageText = sMessage.MessageText;
            sMessage.Answer = "OK";
           /* foreach (ClientInfo InfoFrom in ClientsList)
                if (InfoFrom.cSocket == sock)
                {
                    mes.NickNameToPrivate
                    break;
                }
            /*foreach (InfoTo in ClientsList)
                if (Info.UserNickName == sMessage.NickNameToPrivate)
                    break;*/
        }
        public void ServerShutDown()
        {
            sBase.ShutDownSocket(sSocket);
        }
    }
}
